conf = require("../config")
if not conf.lspconfig.enabled then return {} end

return {
  "neovim/nvim-lspconfig",

  -- example using `opts` for defining servers
  opts = {
    servers = {
      clangd = {},
      basedpyright = {},
      lua_ls = {},
      -- java_langugae_server = {},
      -- svls = {},
      svlangserver = {},
      texlab = {},
      marksman = {},
      rust_analyzer = {
        settings = {
          ["rust-analyzer"] = {
            imports = {
              granularity = {
                group = "module",
              },
              prefix = "self",
            },
              cargo = {
                buildScripts = {
                  enable = true,
                },
              },
            procMacro = {
              enable = true
            },
          }
        },
      },
      jsonls = {},
    }
  },
  config = function(_, opts)

    -- Customizing how diagnostics are displayed
    vim.diagnostic.config({
      virtual_text = false,
      signs = {
        text = {
          [vim.diagnostic.severity.ERROR] = '󰅚 ',
          [vim.diagnostic.severity.WARN] = '󰀪 ',
          [vim.diagnostic.severity.HINT] = '󰌶 ',
          [vim.diagnostic.severity.INFO] = ' ',
        },
        severity = { min = vim.diagnostic.severity.ERROR }, -- only display ERROR
      },
      -- signs = true,
      -- underline = true,
      underline = {
        severity = { min = vim.diagnostic.severity.ERROR }, -- only display ERROR
      },
      update_in_insert = false,
      severity_sort = false,
    })

    -- set diagnostic icons
    -- local signs = { Error = "󰅚 ", Warn = "󰀪 ", Hint = "󰌶 ", Info = " " }
    -- for type, icon in pairs(signs) do
    --   local hl = "DiagnosticSign" .. type
    --   vim.fn.sign_define(hl, { text = icon, texthl = hl, numhl = hl })
    -- end

    -- Set different settings for different languages' LSP
    local lspconfig = require('lspconfig')

    -- Customized on_attach function
    -- See `:help vim.diagnostic.*` for documentation on any of the below functions
    function options(desc)
      M = { noremap = true, silent = true }
      M.desc = desc
    end
    vim.keymap.set('n', '<space>e', vim.diagnostic.open_float, options("show diagnostics in a floating window"))
    vim.keymap.set('n', '[g',       vim.diagnostic.goto_prev,  options("move to the previous diagnostic"))
    vim.keymap.set('n', ']g',       vim.diagnostic.goto_next,  options("move to the next diagnostic"))
    vim.keymap.set('n', '<space>q', vim.diagnostic.setloclist, options("add buffer diagnostics to the location list"))

    -- Use an on_attach function to only map the following keys
    -- after the language server attaches to the current buffer
    local on_attach = function(client, bufnr)
      -- Enable completion triggered by <c-x><c-o>
      vim.api.nvim_buf_set_option(bufnr, 'omnifunc', 'v:lua.vim.lsp.omnifunc')
      -- Enable/Disable diagnostic
      vim.diagnostic.enable()
      -- Enable inlay_hint
      vim.lsp.inlay_hint.enable(true, { bufnr = bufnr })
      -- See `:help vim.lsp.*` for documentation on any of the below functions
      function bufopts(desc)
        M = { noremap = true, silent = true, buffer = bufnr }
        M.desc = desc
        return M
      end
      vim.keymap.set('n', 'gD',        vim.lsp.buf.declaration,             bufopts("jump to the declaration"))
      -- vim.keymap.set('n', 'gd',        vim.lsp.buf.definition,              bufopts("jumps to the definition"))
      vim.keymap.set('n', '<space>hh', vim.lsp.buf.hover,                   bufopts("display hover information"))
      -- vim.keymap.set('n', 'gi',        vim.lsp.buf.implementation,          bufopts("list all the implementations"))
      vim.keymap.set('n', '<space>ss',  vim.lsp.buf.signature_help,          bufopts("display signature information"))
      vim.keymap.set('n', '<space>wa', vim.lsp.buf.add_workspace_folder,    bufopts("add the folder at path to the workspace folders"))
      vim.keymap.set('n', '<space>wr', vim.lsp.buf.remove_workspace_folder, bufopts("remove the folder at path from the workspace folders"))
      vim.keymap.set('n', '<space>wl', function()
        print(vim.inspect(vim.lsp.buf.list_workspace_folders()))
      end, bufopts("list workspace folders"))
      vim.keymap.set('n', '<space>D',  vim.lsp.buf.type_definition,         bufopts("jump to the definition of the type"))
      vim.keymap.set('n', '<space>rn', vim.lsp.buf.rename,                  bufopts("rename all references to the symbol"))
      vim.keymap.set('n', '<space>ca', vim.lsp.buf.code_action,             bufopts("select a code action available"))
      -- vim.keymap.set('n', 'gr',        vim.lsp.buf.references,              bufopts("list all the references to the symbol"))
      vim.keymap.set("n", "<space>f", function()
        vim.lsp.buf.format({ async = true })
      end, bufopts("format a buffer"))
    end

    local border = 'rounded'
    -- LSP settings (for overriding per client)
    local handlers =  {
      ["textDocument/hover"] =  vim.lsp.with(vim.lsp.handlers.hover, {border = border}),
      ["textDocument/signatureHelp"] =  vim.lsp.with(vim.lsp.handlers.signature_help, {border = border }),
    }

    -- To instead override globally
    local orig_util_open_floating_preview = vim.lsp.util.open_floating_preview
    function vim.lsp.util.open_floating_preview(contents, syntax, opts, ...)
      opts = opts or {}
      opts.border = opts.border or border
      return orig_util_open_floating_preview(contents, syntax, opts, ...)
    end

    -- LSP
    local has_cmp, cmp_nvim_lsp = pcall(require, "cmp_nvim_lsp")
    local has_blink, blink = pcall(require, "blink.cmp")
    local capabilities = vim.tbl_deep_extend(
      "force",
      {},
      vim.lsp.protocol.make_client_capabilities(),
      has_cmp and cmp_nvim_lsp.default_capabilities() or {},
      has_blink and blink.get_lsp_capabilities() or {}
    )
    for server, config in pairs(opts.servers) do
      config.capabilities = capabilities
      config.on_attach = on_attach
      config.handlers = handlers
      lspconfig[server].setup(config)
    end

  end
}
